/*
 * Copyright (c) 2012 Sean Connelly
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//
// Pre-defined metatypes
//

exports.value = require('./dyn-tree.js').create()
	.add('basetype_array', {
			passBy: 'ref',
			bodyType: 'none',
			params: ['type']
		})
	.add('basetype_big', {
			passBy: 'val',
			bodyType: 'none',
			params: []
		})
	.add('basetype_blob', {
			passBy: 'val',
			bodyType: 'none',
			params: []
		})
	.add('basetype_code', {
			passBy: 'val',
			bodyType: 'none',
			params: []
		})
	.add('basetype_complex', {
			passBy: 'val',
			bodyType: 'none',
			params: ['type']
		})
	.add('basetype_label', {
			passBy: 'val',
			bodyType: 'none',
			params: []
		})
	.add('basetype_list', {
			passBy: 'ref',
			bodyType: 'none',
			params: ['type']
		})
	.add('basetype_monitor', {
			passBy: 'val',
			bodyType: 'none',
			params: ['type']
		})
	.add('basetype_pointer', {
			passBy: 'val',
			bodyType: 'none',
			params: ['type']
		})
	.add('basetype_ratio', {
			passBy: 'val',
			bodyType: 'none',
			params: []
		})
	.add('basetype_table', {
			passBy: 'ref',
			bodyType: 'none',
			params: ['type', 'type']
		})
	.add('basetype_text', {
			passBy: 'val',
			bodyType: 'none',
			params: []
		})
	.add('basetype_ubig', {
			passBy: 'val',
			bodyType: 'none',
			params: []
		})
	.add('class', {
			passBy: 'ref',
			bodyType: 'class',
			params: ['*type']
		})
	.add('constant', {
			passBy: 'child',
			bodyType: 'none',
			params: ['type']
		})
	.add('copytype', {
			passBy: 'child',
			bodyType: 'none',
			params: ['type']
		})
	.add('enum', {
			passBy: 'val',
			bodyType: 'symbols',
			params: ['*type']
		})
	.add('handle', {
			passBy: 'val',
			bodyType: 'none',
			params: []
		})
	.add('interface', {
			passBy: 'ref',
			bodyType: 'classface',
			params: ['*type']
		})
	.add('macro', {
			passBy: 'none',
			bodyType: 'macro',
			params: ['macro']
		})
	.add('numbound', {
			passBy: 'val',
			bodyType: 'none',
			params: ['expr', 'expr']
		})
	.add('numcycle', {
			passBy: 'val',
			bodyType: 'none',
			params: ['expr', 'expr']
		})
	.add('numfloat', {
			passBy: 'val',
			bodyType: 'none',
			params: ['expr']
		})
	.add('static', {
			passBy: 'child',
			bodyType: 'static',
			params: ['type']
		})
	.add('struct', {
			passBy: 'val',
			bodyType: 'struct',
			params: ['*type']
		})
	.add('superface', {
			passBy: 'ref',
			bodyType: 'classface',
			params: ['*type']
		})
	.add('symbol', {
			passBy: 'val',
			bodyType: 'symbols',
			params: ['*type']
		})
	.add('union', {
			passBy: 'runtime',
			bodyType: 'none',
			params: ['*type']
		})
	.add('union_all', {
			passBy: 'runtime',
			bodyType: 'none',
			params: []
		})
	.addGenerator('^tensor([0-9]+)d$', function(match) {
			// tensor0d (no zero dimension tensors) and tensor0123d (no leading zeros) are invalid
			if (match[1].substr(0, 1) == '0')
				throw 'invalid tensor dimension: "' + match[1] + '"';
			// else, valid tensor

			var dim = parseInt(match[1], 10); // grab dimension
			var params = ['type']; // first parameter of a tensor is the type
			for (var i = 0; i < dim; i++)
				params.push('expr'); // for each dimension, there is an integer size

			return {
					passBy: 'ref',
					bodyType: 'none',
					params: params,
				};
		});
